package br.iesb.importer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import br.iesb.bean.Posicao;
import br.iesb.bean.Tabuleiro;
import br.iesb.bean.boat.ETiro;
import br.iesb.bean.boat.Embarcacao;

public class XMLImporter {

	public Tabuleiro importar(File arquivo) {
		try {
			if (arquivo.canRead() && arquivo.getName().toLowerCase().endsWith(".xml")) {
				BufferedReader br = new BufferedReader(new FileReader(arquivo));
				Tabuleiro tabuleiro = new Tabuleiro();
				String xmlCompleto = "";
				while (br.ready()) {
					String linha = br.readLine();
					xmlCompleto = xmlCompleto + linha.trim();
					if (!linha.startsWith("<?xml")) {
						if (linha.startsWith("<tabuleiro")) {
							StringTokenizer tokenizer = new StringTokenizer(linha, " ");
							while (tokenizer.hasMoreElements()) {
								String token = tokenizer.nextToken();
								if (!token.startsWith("<tabuleiro")) {
									lerAtributosTabuleiro(tabuleiro, token);
									break;
								}
							}
						}
					}
				}
				
				Pattern regex = Pattern.compile("<embarcacao>(.*?)</embarcacao>");
				Matcher matcherString = regex.matcher(xmlCompleto);
				String embarcacao = null;
				List<Embarcacao> colEmbarcacao = new ArrayList<Embarcacao>();
				while(matcherString.find()) {
					Embarcacao emb = new Embarcacao();
					embarcacao = matcherString.group();
					setarElementosEmbarcacao(embarcacao, emb);
					colEmbarcacao.add(emb);
				}
				tabuleiro.setColEmbarcacao(colEmbarcacao);
				
				regex = Pattern.compile("<posicoes>(.*?)</posicoes>");
				matcherString = regex.matcher(xmlCompleto);
				
				if (matcherString.find()) {
					regex = Pattern.compile("<posicao>(.*?)</posicao>");
					matcherString = regex.matcher(matcherString.group());
					List<Posicao> colPosicao = new ArrayList<Posicao>();
					while (matcherString.find()) {
						Posicao p = gerarPosicao(matcherString.group());
						colPosicao.add(p);
					}
					tabuleiro.setPosicoes(colPosicao);
				}
				return tabuleiro;
			}
			return null;
		}catch(Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	private String retornaValorElemento(String xmlElemento, String regexpToParsing){
		Pattern regexp = Pattern.compile(regexpToParsing);
		Matcher matcherString = regexp.matcher(xmlElemento);
		if(matcherString.find()) {
			return matcherString.group(1);
		}else {
			return null;
		}
	}
	
	private void setarElementosEmbarcacao(String embarcacao, Embarcacao emb) throws InstantiationException, IllegalAccessException, NumberFormatException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
		for (Field f : Embarcacao.class.getDeclaredFields()) {
			if (!f.getName().toLowerCase().contains("posic")) {
				String regex = String.format("<%s>(.*?)</%s>", f.getName(), f.getName());
				String valorAtributo = retornaValorElemento(embarcacao, regex);
				if (f.getType().equals(Integer.TYPE)) {
					for (Method m : Embarcacao.class.getDeclaredMethods()) {
						if (m.getName().equalsIgnoreCase("set"+f.getName())) {
							m.invoke(emb, Integer.parseInt(valorAtributo));
							break;
						}
					}
				}
				if (f.getName().equalsIgnoreCase("nome")) {
					Embarcacao.class.getMethod("setNome", String.class).invoke(emb, valorAtributo);
				}
				if (f.getName().equalsIgnoreCase("inHorizontal")) {
					Embarcacao.class.getMethod("setInHorizontal", Boolean.TYPE).invoke(emb, Boolean.parseBoolean(valorAtributo));
				}
			}else {
				if (f.getName().equalsIgnoreCase("posicaoInicial")) {
					String expressao = String.format("<%s>(.*?)</%s>", f.getName(), f.getName());
					Pattern regex = Pattern.compile(expressao);
					Matcher matcherString = regex.matcher(embarcacao);
					String posicaoInicial = null;
					while(matcherString.find()) {
						posicaoInicial = matcherString.group();
						Posicao p = gerarPosicao(posicaoInicial);
						Embarcacao.class.getMethod("setPosicaoInicial", Posicao.class).invoke(emb, p);
					}
				}
				if (f.getName().equalsIgnoreCase("posicoesOcupadas")) {
					Pattern regexPosicoesOcupadas = Pattern.compile("<posicao>(.*?)</posicao>");
					Matcher matcherPosicoesOcupadas = regexPosicoesOcupadas.matcher(embarcacao);
					List<Posicao> posicoesOcupadas = new ArrayList<Posicao>();
					while(matcherPosicoesOcupadas.find()) {
						String posicao = matcherPosicoesOcupadas.group();
						Posicao p = gerarPosicao(posicao);
						posicoesOcupadas.add(p);
					}	
				}
				
			}
		}
		
	}
	
	private Posicao gerarPosicao(String posicaoInicial){
		int linha;
		int coluna;
		boolean inOcupada;
		String estado;
		
		String valorLinha = retornaValorElemento(posicaoInicial, "<linha>(.*?)</linha>");
		linha = Integer.parseInt(valorLinha);
		
		String valorColuna = retornaValorElemento(posicaoInicial, "<coluna>(.*?)</coluna>");
		coluna = Integer.parseInt(valorColuna);
		
		String valorInOcupada = retornaValorElemento(posicaoInicial, "<inOcupada>(.*?)</inOcupada>");
		inOcupada = Boolean.parseBoolean(valorInOcupada);
		
		String valorEstado = retornaValorElemento(posicaoInicial, "<estado>(.*?)</estado>");
		estado = valorEstado;
		
		Posicao retorno;
		if (estado != null && !estado.equalsIgnoreCase("null")) {
			retorno = new Posicao(linha, coluna, ETiro.valueOf(estado));
		}else {
			retorno = new Posicao(linha, coluna);
		}
		retorno.setInOcupada(inOcupada);
		return retorno;
		
	}

	private void lerAtributosTabuleiro(Tabuleiro tabuleiro, String token) throws IllegalAccessException, InvocationTargetException {
		String atributo = token.split("=")[0];
		String valor = token.split("=")[1].replace("'", "");
		for (Method m : Tabuleiro.class.getMethods()) {
			if (("set"+atributo).equalsIgnoreCase(m.getName())) {
				m.invoke(tabuleiro, Integer.parseInt(valor));
				break;
			}
		}
	}
	
	public static void main(String[] args) {
		new XMLImporter().importar(new File("/Users/pedro/Desktop/batalhaNaval/arquivo.xml"));
	}
	
	
}
